package com.tinymall.service.impl;

import com.alibaba.fastjson.JSON;
import com.tinymall.common.exception.UserExistException;
import com.tinymall.common.pojo.dto.UserDTO;
import com.tinymall.common.pojo.entity.User;
import com.tinymall.common.pojo.vo.UserVO;
import com.tinymall.mapper.UserMapper;
import com.tinymall.security.JwtConst;
import com.tinymall.service.IUserService;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: 用户模块的实现类
 * @Author: TX
 * @Date: 2022/7/5 10:28
 * @Version: V1.0.0
 */
@Service
@Slf4j
public class UserServiceImpl implements IUserService {
    @Value("${tinymall.security.key}")
    private String secretKey;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private AuthenticationManager authenticationManager;

    /**
     * 处理用户注册功能
     *
     * @param userDTO
     */
    @Override
    public void reg(UserDTO userDTO) {
        log.info("进入用户注册服务层！！！");
        UserVO userVO = userMapper.selectUserByUsername(userDTO.getUsername());
        // 如果用户为空则注册用户，如果不为空则抛出异常，用户已存在
        if (userVO != null) {
            throw new UserExistException("用户名已存在");
        }
        User user = new User();
        BeanUtils.copyProperties(userDTO, user);
        String encode = PasswordEncoderFactories.createDelegatingPasswordEncoder().encode(user.getPassword());
        System.out.println("用户密码：" + encode);
        user.setPassword(encode);
        userMapper.insertUser(user);
        log.info("用户注册成功！！！");
    }

    @Override
    public UserVO login(UserDTO userDTO) {
        log.info("进入了用户登录界面");
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDTO.getUsername(), userDTO.getPassword());

        // 调用AuthenticationManager验证用户名与密码
        // 执行认证，如果此过程没有抛出异常，则表示认证通过，如果认证信息有误，将抛出异常
        Authentication authenticate = authenticationManager.authenticate(authentication);

        // 如果程序可以执行到此处，则表示登录成功
        // 生成此用户数据的JWT
        // Claims
        org.springframework.security.core.userdetails.User user = (org.springframework.security.core.userdetails.User) authenticate.getPrincipal();
        System.out.println("从认证结果中获取Principal=" + user.getClass().getName());
        // 注意：先将permissions转换成JSON字符串再写入
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtConst.KEY_USERNAME, user.getUsername());
        claims.put(JwtConst.KEY_PASSWORD, JSON.toJSONString(user.getPassword()));
        claims.put(JwtConst.KEY_ROLE, JSON.toJSONString(user.getAuthorities()));
        System.out.println("即将向JWT中写入数据=" + claims);

        String jwt = Jwts.builder()
                // Header：指定算法与当前数据类型
                // 格式为： { "alg": 算法, "typ": "jwt" }
                .setHeaderParam(Header.CONTENT_TYPE, "HS256")
                .setHeaderParam(Header.TYPE, Header.JWT_TYPE)
                // Payload：通常包含Claims（自定义数据）和过期时间
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + 5 * 60 * 1000))
                // Signature：由算法和密钥（secret key）这2部分组成
                .signWith(SignatureAlgorithm.HS256, secretKey)
                // 打包生成
                .compact();

        // 返回JWT数据

        UserVO userVO = new UserVO();
        userVO.setUsername(user.getUsername());
        UserVO userVO1 = userMapper.selectUserByUsername(user.getUsername());
        userVO.setRole(userVO1.getRole());
        userVO.setStatus(1);
        userVO.setJwt(jwt);
        return userVO;
    }
}
